
// import React, {useState} from 'react';
// function App(props) {
//   const propsCount = props.count || 0
//   const [count, setState] = useState(() => propsCount)
//   const [person, setPerson] = useState({name:'张三', age: 18})
//   // 将设置状态值的方法封装在一个函数中
//   function handleCount() {
//     setState(count => {
//       return count + 1
//     })
//     console.log(123) // 由于setState函数是异步的所以这里会先输出
//   }
//   return <div>
//     <span>{count}</span>
//     <span>{person.name}</span>
//     <button onClick={handleCount}>+1</button>
//     <button onClick={() => setPerson({...person, name: '李四'})}>改名字</button>
//   </div>
// }

// -------------------------useReducer------------------------------------------------
// import React, { useReducer } from 'react'
// function App() {
//   function reducer(state, action) {
//     switch(action.type){
//       case 'increment':
//         return state + action.payload
//       case 'decrement':
//         return state - 1
//       default: 
//         return state
//     }
//   }
//   const [count, dispatch] = useReducer(reducer, 0)
//   return <div>
//     <button onClick={() => dispatch({type: 'decrement'})}> - </button>
//     <span>{count }</span>
//     <button onClick={() => dispatch({type: 'increment', payload: 5})}> + </button>
//   </div>
// }
// export default App

// ----------------------------------useContext--------------------------------------
// import React, {useContext, createContext} from 'react'
// const countContext = createContext()
// function App(){
//   return <countContext.Provider value={20}>
//     <Foo></Foo>
//   </countContext.Provider>
// }
// function Foo(){
//   // 简化Consumer的写法,简化获取数据时的代码
//   const value = useContext(countContext)
//   return <div>我是Foo组件{value}</div>
// }
// export default App

// ---------------------------------------useEffect-------------------------------------------
// import React, {useEffect, useState} from 'react'
// import ReactDOM from 'react-dom'
// function App() {
//   const [ count, setCount ] = useState(0)
//   const [ person, setPerson ] = useState({name: '张三', age: 18})
//   // 相当于 componentDidMount, componentDidUpdate
//   // useEffect(() => {
//   //   console.log('组件挂载完成和组件数据更新完成后执行')
//   // })
//   // 相当于componentDidMount
//   useEffect(() => {
//     console.log('组件挂载完成后执行')
//   }, [])
//   // 相当于componentWillUnMount
//   // useEffect(() => {
//   //   return () => {
//   //     console.log('组件销毁之前执行')
//   //   }
//   // })
//   return <div>
//     <span>{count}</span>
//     <span>{person.name}</span>
//     <span>{person.age}</span>
//     <button onClick={() => setCount(count + 1)}>+</button>
//     <button onClick={() => setPerson({...person, age: person.age + 1})}>年龄加</button>
//     <button onClick={() => ReactDOM.unmountComponentAtNode(document.getElementById('root'))}>销毁组件</button>
//   </div>
// }
// export default App

// 使用:
// import React, { useState, useEffect } from 'react'
// import ReactDOM from 'react-dom'
// function App(){
//   const [count, setCount] = useState(0)
//   // 相当于 componentDidMount 和 componentWillUnMount
//   useEffect(() => {
//     let timer = setInterval(() => {
//       setCount(count => {
//         document.title = count + 1
//         return count + 1
//       })
//     }, 1000)
//     // 返回一个函数作用时卸载组件
//     return () => {
//       clearInterval(timer)
//     }
//   }, [])
//   return <div>
//     <span>{count}</span>
//     <button onClick={() => ReactDOM.unmountComponentAtNode(document.getElementById('root'))}>卸载组件</button>
//   </div>
// }
// export default App

// import React, { useEffect } from 'react'
// function App() {
//   // getData().then(res => {
//   //   console.log(res)
//   // })
//   useEffect(() => {
//     // useEffect中的参数函数不能是异步函数promise,所以需要通过处理返回来执行
//     (async () => {
//       let res = await getData()
//       console.log(res)
//     })()
//   }, [])
//   return <div>
//     useEffe内搭配异步函数
//   </div>
// }
// function getData() {
//   return new Promise(resolve => {
//     resolve({msg: 'Hello World'})
//   })
// }
// export default App

// -----------------------------------useMemo-------------------------------------
// import React, {useState, useMemo} from 'react'

// function App() {
//   const [ count, setCount ] = useState(0)
//   const [ bool, setBool ] = useState(true)
//   // 第二个参数可以规定监听哪些值的变化,即使内部不做返回处理,只要监听的值变化就会执行第一个参数回调函数
//   const result = useMemo(() => {
//     return count * 2
//   },[count])
//   return (
//     <div>
//       <span>{count},</span>
//       <span>{result},</span>
//       <span>{bool? '真': '假'}</span>
//       <button onClick={() => setCount(count + 1)}>+</button>
//       <button onClick={() => setBool(!bool)}>真假</button>
//     </div>
//   )
// }
// export default App

// memo:
// import React, {useState, memo} from 'react'
// function App() {
//   const [count, setCount] = useState(0)
//   return (
//     <div>
//       <span>{count}</span>
//       <button onClick={() => setCount(count + 1)}>+</button>
//       <Foo></Foo>
//     </div>
//   )
// }
// let Foo = () => {
//   console.log('Foo组件渲染了')
//   return <div>Foo组件渲染了</div>
// }
// Foo = memo(Foo)

// export default App

// ----------------------------useCallback----------------------------
// import React, {useState, memo, useCallback} from 'react'

// function App() {
//   const [count, setCount] = useState(0) 
//   // 这里每次都会重新渲染一个函数,传递给Foo的每次都是不同的函数,即使使用了memo还是会重新渲染
//   // const resetCount = () => {  
//   //   setCount(0)
//   // }
//   // 使用useCallback传递的是同一个函数, 不根据当前App函数组件的变化而变换
//   const resetCount = useCallback(() => {
//     setCount(0)
//   }, [setCount])
//   return (
//     <div>
//       <span>{count}</span>
//       <button onClick={() => setCount(count + 1)}>+</button>
//       <Foo resetCount={resetCount}></Foo>
//     </div>
//   )
// }
// let Foo = (props) => {
//   console.log('foo组件重新渲染了')
//   return <div>
//     Foo组件
//     <button onClick={props.resetCount}>重置count</button>
//   </div>
// }
// Foo = memo(Foo)

// export default App

// ---------------------------------useRef------------------------------------
// import React, {useRef} from 'react'
// function App() {
//   const ref = useRef()
//     // {current: div}
//   return <div ref={ref}>
//     <button onClick={() => console.log(ref)}>查看当前ref</button>  
//   </div>
// }
// export default App

// 保存数据：
// import React, {useEffect, useRef, useState} from 'react'
// function App() {
//   const [count, setCount] = useState(0)
//   let timer = useRef()
//   useEffect(() => {
//     timer.current = setInterval(() => {
//       // 闭包传递count
//       setCount(count => count+1)
//     }, 200)
//   }, [])
//   const stopCount = () => {
//     console.log(timer)
//     clearInterval(timer.current)
//   }
//   return <div>
//     {count}
//     <button onClick={stopCount}>清除定时器</button>
//   </div>
// }
// export default App

// -------------------自定义Hook----------------------
// import React, {useEffect, useState} from 'react'
// import axios from 'axios'
// function useGetPost() {
//   const [post, setPost] = useState('')
//   useEffect(() => {
//     axios.get('https://jsonplaceholder.typicode.com/posts/1').then((res) => {
//       setPost(res.data)
//     })
//   }, []) 
//   return [post, setPost]
// }

// function App() {
//   const [post] = useGetPost()
//   return <div>
//     <div>{post.title}</div>
//     <div>{post.body}</div>
//   </div>
// }
// export default App

// -----------------自定义Hook 2-------------------
// import React, { useState } from 'react'
// function useUpdateInput(initialValue) {
//   const [value, setValue] = useState(initialValue)
//   return {
//     value,
//     onChange: (e) => setValue(e.target.value)
//   }
// }
// function App(){
//   const username = useUpdateInput('')
//   const password = useUpdateInput('')
//   const submitForm = (e) => {
//     e.preventDefault()
//     console.log('username',username.value)
//     console.log('password',password.value)
//   }
//   return <form onSubmit={submitForm}>
//     <input {...username}></input>
//     <input {...password}></input>
//     <input type='submit'/>
//   </form>
// }
// export default App

// ----------------------路由hook----------------------
// import React from 'react'
// import {Link, Route} from 'react-router-dom'
// import Home from './home/home'
// import List from './list/list'

// function App() {
//   return <div>
//     <div>
//       <Link to="/home/zhangsan">首页</Link>
//       <Link to="/list">列表</Link>
//     </div>
//     <div>
//       <Route path="/home/:name" component={Home}></Route>
//       <Route path="/list" component={List}></Route>
//     </div>
//   </div>
// }

// export default App

// ------useState钩子函数原理------useEffect钩子函数原理-----------------

import React from 'react'
import ReactDOM from 'react-dom'
// 将保存state和设置state的函数初始化为数组,并初始化一个下标用来更新不同的state. 不是数组的话只能更新一个
// uesEffect函数第二参数是一个数组,所以这里需要定义一个二维数组来保存,才能实现不同的useEffect函数监听不同的依赖值变化
let state = []
let setStates = []
let stateIndex = 0
let preDepsArr = [] // 二维数组[[], []]
let effectIndex = 0
// 通过闭包的形式传递下标,从而更改相对应的state的值
function createSetter(index) {
  return function(newState) {
    state[index] = newState
    render()
  }
}
function useState(initialState) {
  // 判断是否有值
  state[stateIndex] = state[stateIndex] || state[stateIndex] === 0 ? state[stateIndex] : initialState
  // 保存设置state的方法
  setStates[stateIndex] = createSetter(stateIndex)
  // 缓存state和设置state的方法
  let value = state[stateIndex]
  let setState = setStates[stateIndex]
  // 下标+1
  stateIndex++
  // 返回一个数组包含state, 设置state的方法
  return [value, setState]
}
function useEffect(callback, depsArr) {
  // 判断callback是不是函数
  if(Object.prototype.toString.call(callback) !== '[object Function]') throw new TypeError('useEffect第一个参数必须是函数')
  // 如果没有传递第二个参数则直接执行第一个参数回调函数
  if(!depsArr) {
    callback()
  }else {
    if(Object.prototype.toString.call(depsArr) !== '[object Array]') throw new TypeError('useEffect第二个参数必须是数组')
    // 获取上一次状态值
    let prevDeps = preDepsArr[effectIndex]
    // 将当前的依赖值和上一次的依赖值做对比，如果有变化，调用callback
    let hasChanged = prevDeps ? depsArr.every((item, index) => item === prevDeps[index]) === false :  true
    // 判断值是否变化,如果发生变化调用callback
    if(hasChanged) {
      callback()
    }
    // 同步最新依赖值
    preDepsArr[effectIndex] = depsArr
    effectIndex++
  }
}


function useReducer(reducer, initialState) {
  const [state, setState] = useState(initialState)
  function dispatch(action){
    const newState = reducer(state, action)
    setState(newState)
  }
  return [state, dispatch]
}
// 当数据发生变化时重新渲染组件,并且该函数内需要将下标归0,因为每次渲染都会重新执行一次,所以必须归0
function render(){
  stateIndex = 0
  effectIndex = 0
  ReactDOM.render(<App></App>, document.getElementById('root'))
}
function App() {
  // const [count, setCount] = useState(1)
  // const [name, setName] = useState('张三')
  // useEffect(() => {
  //   console.log(123)
  // }, [count])
  // useEffect(() => {
  //   console.log(321)
  // }, [name])
  function reducer(state, action) {
    switch(action.type) {
      case 'increment':
        return state + 1
      case 'decrement':
        return state - 1
      default:
        return state
    }
  }
  const [count, dispatch] = useReducer(reducer, 0)
  return <div>
    {count}
    <button onClick={() => dispatch({type: 'increment'})}>+</button>
    <button onClick={() => dispatch({type: 'decrement'})}>-</button>
  </div>
}
export default App